package com.itheima.stock.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.stock.constant.StockConstant;
import com.itheima.stock.pojo.domain.UserDomain;
import com.itheima.stock.pojo.vo.req.LoginReqVo;
import com.itheima.stock.pojo.vo.req.UserReqVo;
import com.itheima.stock.pojo.vo.resp.R;
import com.itheima.stock.pojo.vo.resp.ResponseCode;
import com.itheima.stock.security.user.LoginUserDetail;
import com.itheima.stock.security.utils.JwtTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证过滤器
 */

public class JwtLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private RedisTemplate redisTemplate;

    /**
     * 自定义构造器,传入登录认证的url地址
     * @param loginUrl
     */
    public JwtLoginAuthenticationFilter(String loginUrl) {
        super(loginUrl);
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (!request.getMethod().equals("POST") ||
                ! (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE))) {
            throw new AuthenticationServiceException(ResponseCode.AUTHENTICATION_METHOD_NOT_SUPPORTED + request.getMethod());
        }
        LoginReqVo reqVo = new ObjectMapper().readValue(request.getInputStream(), LoginReqVo.class);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("utf-8");
        //判断验证码是否为空
        if (StringUtils.isBlank(reqVo.getCode()) || StringUtils.isBlank(reqVo.getSessionId())) {
            R<Object> error = R.error(ResponseCode.CHECK_CODE_NULL);
            String jasonData = new ObjectMapper().writer().writeValueAsString(error);
            response.getWriter().write(jasonData);
            return null;
        }
        String redisCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + reqVo.getSessionId());
        //判断验证码是否过期
        if (StringUtils.isBlank(redisCode)) {

            R<Object> error = R.error(ResponseCode.CHECK_CODE_TIMEOUT);
            String jasonData = new ObjectMapper().writer().writeValueAsString(error);
            response.getWriter().write(jasonData);
            return null;
        }
        //判断redis中缓存的验证码与输入的验证码是否匹配()忽略大小写
        if (!redisCode.equalsIgnoreCase(reqVo.getCode())) {
            R<Object> error = R.error(ResponseCode.CHECK_CODE_ERROR);
            String jasonData = new ObjectMapper().writer().writeValueAsString(error);
            response.getWriter().write(jasonData);
            return null;
        }
        String username = reqVo.getUsername();
        username = username != null ? username : "";
        username = username.trim();
        String password = reqVo.getPassword();
        password = password != null ? password : "";

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        return this.getAuthenticationManager().authenticate(authRequest);//提供完票据之后去UserDetailsServiceImpl比对
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        LoginUserDetail principal = (LoginUserDetail)authResult.getPrincipal();//获取认证信息
        String username = principal.getUsername();
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        String tokenStr = JwtTokenUtil.createToken(username, authorities.toString());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("utf-8");
        UserDomain user = new UserDomain();
        BeanUtils.copyProperties(principal,user);
        user.setAccessToken(tokenStr);
        response.getWriter().write(new ObjectMapper().writeValueAsString(R.ok(user)));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        request.setCharacterEncoding("utf-8");
        response.getWriter().write(new ObjectMapper().writeValueAsString(R.error(ResponseCode.ERROR)));
    }
}
